home *** CD-ROM | disk | FTP | other *** search
/ BCI NET / BCI NET Dec 94.iso / archives / programming / utilities / isan.lha / ISAN / ISAN.s < prev    next >
Text File  |  1994-03-09  |  57KB  |  1,873 lines

  1. *************************************************************************************
  2. * ISAN: Instruction Stream ANalyzer  v1.2        © Jan 1994 L. Vanhelsuwé
  3. * ---------------------------------------        ------------------------
  4. *
  5. * Usage: ISAN <TASK $tcb_addr|PROCESS procnum>
  6. *
  7. * ISAN Is used to get an idea of which instructions a particular Exec Task or
  8. * AmigaDOS Process is executing.
  9. * This is achieved by adding a TRACE exception handler to the Task which keeps
  10. * track of how many times a particular instruction or group of instructions has
  11. * been executed.
  12. * In parallel another Process (ISAN itself) regularly uses the results produced
  13. * by the exception handler to display the statistics graphically in a Window.
  14. *
  15. * The instructions of interest are listed in a run-time file called ISAN.config.
  16. * This file basically lists the numeric opcodes with a string to be used as
  17. * "label" for this opcode.
  18. *
  19. * History:
  20. * --------
  21. * Tue 17/MAR/92: Started project (coded all initialization first)
  22. * Wed 18/MAR/92: Got first tracing to work, added pattern mask feature
  23. * Thu 19/MAR/92: Added TOTAL option
  24. * Fri 20/MAR/92: Added Topaz font selection for Text output. Cleaned up code/comments.
  25. * Tue 14/APR/92: Added Graphical Opcode Usage Mapping (pixels represent each opcode)
  26. * Tue 21/APR/92: Added counters reset option (by clicking in window)
  27. * Tue 28/APR/92: Fixed 'Task not found' bug. Embarrassing...
  28. * Sat 02/MAY/92: Added task register monitoring option
  29. * Sun 03/MAY/92: Optimized TRACE exception handler by using memory indirect adr modes.
  30. * Tue 05/MAY/92: Fixed OpenWindow() failure bug (SORRY!!)
  31. * Sun 09/JAN/94: Added FILE keyword to command line options
  32. * Sat 22/JAN/94: Added PROFILE keyword for simplistic MODE 2 PC profiling
  33. *
  34. *************************************************************************************
  35.  
  36.         include    std            ;include std macros, equates
  37.         include    hardware/custom.i    ;for intena reg
  38.  
  39.  
  40.         RSRESET    Opcode    ; Opcode Descriptor structure
  41. opc_base_op    RS.W    1        ;base opcode binary pattern (opcode template)
  42. opc_nocare_mask    RS.W    1        ;mask for bits which can be anything
  43. opc_combis    RS.W    1        ;# of combinations that mask gives us
  44. opc_label    RS.L    1        ;ptr to opcode mnemonic string
  45. opc_label_len    RS.W    1        ;length of label string (for Text() )
  46. opc_freq    RS.L    1        ;copy of the counter found in big array
  47. opc_xfreq    RS.L    1        ;normalized frequency
  48. opc_sizeof    rs.w    0
  49.  
  50. CNTS_BLOCKSIZE    equ    65536*4        ;each 680x0 opcode has a LONG counter
  51.  
  52. MAX_PC_HIST    equ    248        ;max number of PCs remembered.
  53.  
  54. CHAR_WIDTH    equ    8        ;for Topaz80
  55. CHAR_HEIGHT    equ    8
  56.  
  57. WINDOW_WIDTH    equ    482        ;width excluding fat right border
  58. PANE_X        equ    6        ;top-left offsets to body of window
  59. PANE_Y        equ    10
  60. HEXNUM_SPACE    equ    8*CHAR_WIDTH    ;width of frequency field
  61. GADG_WIDTH    equ    17        ;width pixels that slider takes up
  62.  
  63. ; Two special illegal opcode words for our "TOTAL" and underline special entries
  64.  
  65. SPECIAL1    equ    $AFFF        ;in the A-line group
  66. SPECIAL2    equ    $AFFE        ;in the A-line group
  67.  
  68. GFXR        MACRO
  69.         move.l    rastport,a1
  70.         GFX    \1
  71.         ENDM
  72.  
  73. _intena        equ    $DFF000+intena    ;for DISABLE/ENABLE macros
  74.  
  75. ;===================================================================================
  76. ;===================================================================================
  77. ;===============                   =================================================
  78. ;=============== START OF PROGRAM  =================================================
  79. ;===============                   =================================================
  80. ;===================================================================================
  81. ;===================================================================================
  82.  
  83. START_ISAN:    move.l    sp,stack_level        ;for clean exits from any call level
  84.         move.l    a0,arg_line        ;remember where CLI arguments are
  85.  
  86.         bsr    init_isan        ;init some vars, ptrs...
  87.  
  88.         bsr    open_libs        ;open DOS,gfx,intui, get stdout
  89.         beq    bail_out        ;quit now if failed.
  90.  
  91.         move.l    4.w,a6            ;check to see that this machine is
  92.         move.w    AttnFlags(a6),d0    ;at least 020 based
  93.         btst    #AFB_68020,d0        ;because I need 020 exception frames
  94.         beq    need_020
  95.  
  96.         bsr    check_args        ;validate argument line
  97.  
  98.         move.l    conf_file,a0        ;attempt to load config file
  99.         bsr    load_file
  100.         beq    cant_find_conf
  101.  
  102.         move.l    d0,conf_size        ;remember config file details
  103.         move.l    a0,conf_buffer        ;for deallocation when exiting
  104.  
  105.         bsr    read_configuration    ;parse config file & create data structs.
  106.  
  107.         move.l    #CNTS_BLOCKSIZE,d0    ;allocate 256K array of 64K LONG
  108.         move.l    #MEMF_CLEAR|MEMF_PUBLIC,d1    ;instruction counters
  109.         EXEC    AllocMem
  110.         move.l    d0,counters
  111.         beq    no_memory        ;exit if failed.
  112.  
  113.         move.l    #MAX_PC_HIST*2*4,d0    ;allocate 2 arrays for PC history
  114.         move.l    #MEMF_CLEAR|MEMF_PUBLIC,d1
  115.         EXEC    AllocMem
  116.         move.l    d0,PC_history_PCs
  117.         beq    no_memory        ;exit if failed.
  118.         add.l    #MAX_PC_HIST*4,d0
  119.         move.l    d0,PC_history_cnts
  120.  
  121.         bsr    open_windows        ;try to get our display window(s)
  122.         beq    cant_get_window        ;error if failed.
  123.  
  124.         tst.l    opcode_map        ;if user also asked for a graphical
  125.         beq    no_map_req        ;view of all opcodes used by Task
  126.  
  127.         bsr    open_screen
  128.         beq    no_screen
  129.  
  130. ;-- At this stage we've got our graphs window, our file, our counters etc...
  131. ;-- Now is the time to do the tricky bit: open heart surgery on an unsuspecting Task!
  132.  
  133. no_map_req    bsr    start_task_traceing    ;enable TRACE mode of selected Task
  134.  
  135. ;---------------
  136. main_loop    move.l    DOS_LIB_PTR,a6        ;depending on slider gadget setting:
  137.         move.l    update_speed,d1
  138.         DOS    Delay            ;slow down graphical stats updating
  139.  
  140.         bsr    scan_stats        ;go through opcode list & stats and
  141.         bsr    update_windows        ;update window graphs
  142.         bsr    update_screen        ;and opcode bitmap (if enabled)
  143.  
  144.         bsr    handle_IDCMP        ;check slider gadget & close gadget
  145.  
  146.         tst.b    close_me        ;user clicked on CLOSE gadget ?
  147.         beq    main_loop        ;no: do main loop again
  148.  
  149.         bsr    stop_task_traceing    ;switch Task back to non-TRACE mode
  150.  
  151. ;-----------------------------------
  152. ; This is the wind-down bit of ISAN:
  153. ; Close and deallocate everything that we got from system
  154. ;-----------------------------------
  155.  
  156. bail_out    move.l    GFX_LIB_PTR,a6        ;doing Graphics closures...
  157.  
  158.         move.l    font_ptr,d0        ;did we successfuly get Topaz font?
  159.         beq    no_font
  160.         move.l    d0,a1
  161.         GFX    CloseFont        ;yes, then release before quiting.
  162. ;---------------
  163. no_font        move.l    INTUI_LIB_PTR,a6    ;doing Intuition closures...
  164.  
  165.         move.l    window,d0        ;if we managed to open our window,
  166.         beq    no_window
  167.         move.l    d0,a0
  168.         INTUI    CloseWindow        ;kill it now.
  169.  
  170. no_window    move.l    regs_window,d0        ;same with registers window
  171.         beq    no_regswindow
  172.         move.l    d0,a0
  173.         INTUI    CloseWindow        ;kill it now.
  174.  
  175. no_regswindow    move.l    prof_window,d0        ;same with PC profiling window
  176.         beq    no_profwindow
  177.         move.l    d0,a0
  178.         INTUI    CloseWindow        ;kill it now.
  179.  
  180. no_profwindow    move.l    map_screen,d0
  181.         beq    no_scr
  182.         move.l    d0,a0
  183.         INTUI    CloseScreen        ;same with opcode map screen
  184. ;---------------
  185. no_scr        move.l    4.w,a6            ;doing Exec closures...
  186.         
  187.         move.l    #MAX_PC_HIST*2*4,d0
  188.         move.l    PC_history_PCs,d1
  189.         beq    no_PC_history
  190.         move.l    d1,a1
  191.         EXEC    FreeMem            ;free PC history if allocated
  192.  
  193. no_PC_history    move.l    array_size,d0
  194.         move.l    opcode_list,d1
  195.         beq    no_opc_list
  196.         move.l    d1,a1
  197.         EXEC    FreeMem            ;free opcodes array if allocated
  198.  
  199. no_opc_list    move.l    #CNTS_BLOCKSIZE,d0
  200.         move.l    counters,d1
  201.         beq    no_counters
  202.         move.l    d1,a1
  203.         EXEC    FreeMem            ;free counters array if allocated
  204.  
  205. no_counters    move.l    conf_size,d0
  206.         beq    release_libs
  207.         move.l    conf_buffer,a1
  208.         EXEC    FreeMem            ;free cached conf file.
  209.  
  210. release_libs    bsr    close_libs        ;finally release our grip on libraries
  211.  
  212.         move.l    stack_level,sp        ;restore original SP (allows quit from
  213. END_ISAN:    rts                ;subroutines)
  214.  
  215. ;===================================================================================
  216. ;===================================================================================
  217. ;===============                   =================================================
  218. ;===============  END OF PROGRAM   =================================================
  219. ;===============                   =================================================
  220. ;===================================================================================
  221. ;===================================================================================
  222.  
  223. ;-----------------------------------------------
  224. ; Parse argument line according to:
  225. ;
  226. ; TASK/K,PROCESS/K,SPEED/K,MODE/K,REGS/S,TOTAL/S,GRAFMAP/S,FILE/K,PROFILE/S
  227. ;
  228. ; e.g. 1> ISAN TASK $7d0432C SPEED 1 MODE 2 TOTAL
  229. ;-----------------------------------------------
  230.  
  231. check_args    bsr    clear_results        ;set default results for ReadArgs
  232.  
  233.         move.l    #ISAN_template,d1    ;our argument template
  234.         move.l    #rda_results,d2
  235.         bsr    ReadArgs        ;parse command line (2.0 style)
  236.         beq    give_syntax        ;malformed arguments ? -> give help
  237.  
  238.         move.l    task_arg,d0        ;if task AND process args are given:
  239.         and.l    process_arg,d0        ;sorry, need exactly one.
  240.         bne    task_or_proc_please
  241.  
  242.         move.l    task_arg,d0        ;if NEITHER task OR process args are
  243.         or.l    process_arg,d0        ;given: sorry need one.
  244.         beq    give_syntax
  245. ;---------------
  246.         tst.l    profile_flag        ;user wants branching/loop profiling ?
  247.         beq    which_mode
  248.         move.l    #1,trace_mode        ;force trace mode to MODE 2
  249.         bra    which_speed        ;skip user's mode selection
  250. ;---------------
  251. which_mode    move.l    trace_mode,a0        ;check out the trace mode argument
  252.         moveq    #0,d0
  253.         move.b    (a0),d0
  254.         cmp.b    #'1',d0            ;trace all instructions (MODE 1) ?
  255.         beq    good_mode
  256.  
  257.         cmp.b    #'2',d0            ;or trace program flow changes (MODE 2)
  258.         bne    wrong_mode
  259. good_mode    sub.b    #'1',d0
  260.         move.l    d0,trace_mode        ;store 0 or 1 (MODE 1 or 2 resp.)
  261. ;---------------
  262. which_speed    move.l    update_speed,a0
  263.         move.l    a0,a4
  264.         bsr    DEC_TO_BIN        ;get SPEED <decimal> argument
  265.         cmp.l    a0,a4            ;if argument wasn't decimal
  266.         beq    invalid_update_sp    ;error!
  267.         tst.l    d1            ;or delay is 0
  268.         beq    invalid_update_sp
  269.  
  270.         move.l    #50*10,d0        ;check that user doesn't give a huge
  271.         cmp.l    d0,d1            ;delay factor coz that would freeze
  272.         bcs    decent_speed        ;our IDCMP loop too !
  273.         move.l    d0,d1
  274. decent_speed    move.l    d1,update_speed        ;else use user value as speed
  275. ;---------------
  276.         move.l    task_arg,d0        ;look for a Task or a Process?
  277.         beq    get_Process
  278.  
  279. get_Task    move.l    d0,a0            ;check task address syntax
  280.         cmp.b    #'$',(a0)+
  281.         bne    want_dollar_hex
  282.  
  283.         bsr    hex_to_bin        ;convert Task hex address to bin
  284.         move.l    d0,tcb_ptr        ;remember Task address
  285.  
  286.         bsr    check_taskaddr        ;validate Task
  287.         bne    task_doesnt_exist    ;if Task exists,
  288.  
  289.         lea    window_info,a0        ;-> window title append position
  290.         move.l    #'TASK',(a0)+        ;regardless of odd allignment (68030 **!!)
  291.         move.w    #' $',(a0)+        ;append string "TASK $hhhhhhhh)",0
  292.         move.l    tcb_ptr,d0
  293.         moveq    #8,d1
  294.         bsr    bin_hex            ;(reconvert Task addr to clean 8 chars)
  295.  
  296.         lea    task_addr_str+8,a0
  297.         move.w    #')'<<8,(a0)+        ;finish off title string
  298.         rts
  299. ;---------------
  300. get_Process    move.l    process_arg,a0        ;-> decimal process number
  301.         move.l    a0,a4
  302.         bsr    DEC_TO_BIN        ;get decimal number
  303.         cmp.l    a0,a4
  304.         beq    bad_procnum
  305.  
  306.         move.l    d1,d7
  307.         bsr    check_process        ;find Process N
  308.         move.l    d2,tcb_ptr        ;if found, store its TCB addr.
  309.         beq    proc_doesnt_exist
  310.  
  311.         lea    window_info,a0        ;now add string "PROCESS N)",0
  312.         move.l    #'PROC',(a0)+        ;to end of window title
  313.         move.l    #'ESS ',(a0)+
  314.         move.l    process_arg,a1
  315.         move.b    (a1)+,(a0)+        ;copy 1st process ID decimal digit
  316.         cmp.b    #9,d7            ;was process number 2 digits ?
  317.         ble    end_title
  318.         move.b    (a1)+,(a0)+        ;copy 2nd digit
  319.  
  320. end_title    move.w    #')'<<8,(a0)+        ;finish off title string
  321.         rts
  322. ;-----------------------------------------------
  323. ; Open graphs Window (sized according to how long opcode list is).
  324. ; Set the TextFont to "topaz 8" so that any Preferences font doesn't
  325. ; screw up our neat display.
  326. ;
  327. ; Return EQ if failed.
  328. ;-----------------------------------------------
  329.  
  330. open_windows    move.l    INTUI_LIB_PTR,a6    ;using Intuition...
  331.         move.l    #MyNewWindow,a0
  332.         INTUI    OpenWindow        ;open output window (incl. slider gadg)
  333.         move.l    d0,window        ;if ISAN.conf list too big then window
  334.         req                ;won't be able to open (too high)
  335.  
  336.         move.l    d0,a0
  337.         move.l    wd_UserPort(a0),msgport    ;also find Window's IDCMP msg port
  338.         move.l    wd_RPort(a0),rastport    ;and graphics RastPort
  339.  
  340.         move.l    GFX_LIB_PTR,a6        ;using graphics.library...
  341.         lea    textattr,a0
  342.         GFX    OpenFont        ;get Topaz 8 ROM font
  343.         move.l    d0,font_ptr
  344.         req
  345.  
  346.         move.l    d0,a0
  347.         GFXR    SetFont            ;use this font for our Window
  348. ;---------------
  349.         tst.l    show_regs        ;should we also open a register info
  350.         beq    no_regswin
  351.  
  352.         move.l    INTUI_LIB_PTR,a6    ;using Intuition again...
  353.  
  354.         move.l    #MyNewWindow,a0        ;modify initial NewWindow struct
  355.         add.w    #(WINDOW_WIDTH-386)/2,nw_LeftEdge(a0)
  356.         move.w    #386,nw_Width(a0)
  357.         move.w    #55,nw_Height(a0)
  358.         move.w    #50,nw_TopEdge(a0)
  359.         clr.l    nw_FirstGadget(a0)
  360.         clr.l    nw_IDCMPFlags(a0)    ;window generates NO messages
  361.         and.l    #~WINDOWCLOSE,nw_Flags(a0)    ;no close gadget on this win.
  362.         
  363.         move.l    #regswin_title,nw_Title(a0)
  364.         INTUI    OpenWindow        ;open output window (incl. slider gadg)
  365.         move.l    d0,regs_window        ;if ISAN.conf list too big then window
  366.         req                ;won't be able to open (too high)
  367.  
  368.         move.l    d0,a0
  369.         move.l    wd_RPort(a0),regswin_rp
  370.  
  371.         move.l    GFX_LIB_PTR,a6        ;switch to graphics library
  372.         move.l    font_ptr,a0
  373.         move.l    regswin_rp,a1
  374.         GFX    SetFont            ;use 8*8 font for our Window
  375.  
  376.         bsr    draw_regswin_txt
  377. ;---------------
  378. no_regswin    tst.l    profile_flag        ;should we also open a PC stats win?
  379.         beq    no_profile_win
  380.  
  381.         move.l    INTUI_LIB_PTR,a6    ;using Intuition again...
  382.         move.l    #MyNewWindow,a0
  383.         move.w    #512,nw_Height(a0)
  384.         move.w    #640,nw_Width(a0)
  385.         clr.w    nw_LeftEdge(a0)
  386.         clr.w    nw_TopEdge(a0)
  387.         clr.l    nw_FirstGadget(a0)
  388.         clr.l    nw_IDCMPFlags(a0)    ;window generates NO messages
  389.         and.l    #~WINDOWCLOSE,nw_Flags(a0)    ;no close gadget on this win.
  390.         
  391.         move.l    #prof_win_title,nw_Title(a0)
  392.         INTUI    OpenWindow        ;open output window (incl. slider gadg)
  393.         move.l    d0,prof_window        ;if ISAN.conf list too big then window
  394.         req                ;won't be able to open (too high)
  395.  
  396.         move.l    d0,a0
  397.         move.l    wd_RPort(a0),profwin_rp ;init its RastPort ptr
  398.  
  399.         move.l    GFX_LIB_PTR,a6        ;switch to graphics library
  400.         move.l    font_ptr,a0
  401.         move.l    profwin_rp,a1
  402.         GFX    SetFont            ;use 8*8 font for our Window
  403.  
  404.         move.l    profwin_rp,a1
  405.         moveq    #1,d0            ;use Black for text
  406.         GFX    SetAPen
  407. ;---------------
  408. no_profile_win    moveq    #-1,d0            ;NE = OK!
  409.         rts
  410. ;-----------------------------------------------
  411. ; Draw some static text in the freshly opened REGISTERS window.
  412. ;-----------------------------------------------
  413. draw_regswin_txt:
  414.         move.l    regswin_rp,a1
  415.         moveq    #1,d0            ;use Black for text
  416.         GFX    SetAPen
  417.  
  418.         lea    regstrings,a3        ;-> strings to print
  419.         moveq    #4-1,d7            ;print 4 lines of 4 registers
  420.         moveq    #PANE_Y+CHAR_HEIGHT,d4
  421.  
  422. pr_regline    moveq    #4-1,d6
  423.         moveq    #PANE_X,d3        ;reset cursor X
  424.  
  425. pr_reg        move.l    regswin_rp,a1
  426.         move.w    d3,d0
  427.         move.w    d4,d1
  428.         GFX    Move
  429.  
  430.         moveq    #3,d0
  431.         move.l    a3,a0
  432.         move.l    regswin_rp,a1
  433.         GFX    Text            ;print a string "Rn="
  434.  
  435.         lea    3(a3),a3        ;point to next string
  436.         add.w    #12*CHAR_WIDTH,d3
  437.         dbra    d6,pr_reg
  438.     
  439.         add.w    #CHAR_HEIGHT,d4        ;go down a line
  440.         dbra    d7,pr_regline
  441. ;---------------
  442.         move.l    regswin_rp,a1
  443.         moveq    #PANE_X,d0        ;reset cursor X
  444.         move.w    d4,d1
  445.         GFX    Move
  446.  
  447.         moveq    #3,d0
  448.         move.l    a3,a0
  449.         move.l    regswin_rp,a1
  450.         GFX    Text            ;"PC="
  451.  
  452.         rts
  453. ;-----------------------------------------------
  454. ; If user requested the GRAFMAP command line option,
  455. ; open lo-res 256*256 screen and draw the nibble reference grid.
  456. ;
  457. ; Every single opcode used by the traced Task will light up one pixel
  458. ; corresponding to its exact opcode (0..65535 !).
  459. ;-----------------------------------------------
  460. open_screen    move.l    INTUI_LIB_PTR,a6    ;because the opcode map screen is so
  461.         move.l    ib_FirstScreen(a6),a0    ;extremely narrow (256 pixels wide),
  462.         move.w    sc_Width(a0),d0        ;find out width of Workbench (+-)
  463.         lsr.w    #1,d0            ;(convert to lores pixels)
  464.         sub.w    #256,d0            ;and center our screen on monitor...
  465.         lsr.w    #1,d0
  466.  
  467.         lea    map_newscreen,a0
  468.         move.w    d0,ns_LeftEdge(a0)
  469.  
  470.         INTUI    OpenScreen        ;open graphical opcode usage display
  471.         move.l    d0,map_screen
  472.         req
  473.  
  474.         move.l    d0,a0
  475.         lea    sc_RastPort(a0),a2
  476.         move.l    GFX_LIB_PTR,a6
  477.  
  478.         move.l    a2,a1
  479.         moveq    #2,d0            ;write reference grid in plane 1
  480.         GFX    SetAPen
  481.  
  482.         moveq    #16-1,d7        ;write 16 horizontal lines
  483.         move.w    #12,d2            ;starting Y with (0,12)-(255,12)
  484.  
  485. draw_horiz    moveq    #0,d0
  486.         move.w    d2,d1
  487.         move.l    a2,a1            ;get RastPort ptr
  488.         GFX    Move
  489.  
  490.         move.w    #255,d0
  491.         move.w    d2,d1
  492.         move.l    a2,a1
  493.         GFX    Draw
  494.  
  495.         add.w    #16,d2            ;increment Y
  496.         dbra    d7,draw_horiz
  497. ;---------------
  498.         moveq    #16-1,d7        ;write 16 vertical lines
  499.         moveq    #0,d2            ;starting with (0,12)-(0,255+12)
  500.  
  501. draw_vert    move.w    d2,d0
  502.         moveq    #12,d1
  503.         move.l    a2,a1
  504.         GFX    Move
  505.  
  506.         move.w    d2,d0
  507.         move.w    #12+255,d1
  508.         move.l    a2,a1
  509.         GFX    Draw
  510.  
  511.         add.w    #16,d2            ;increment X
  512.         dbra    d7,draw_vert
  513.  
  514.         moveq    #-1,d0            ;return OK.
  515.         rts
  516. ;-----------------------------------------------
  517. ; Error EXITS (print error, clean up and quit)
  518. ;-----------------------------------------------
  519. no_memory    lea    no_arr_mem,a0
  520.         bsr    print_error
  521.         bra    bail_out
  522. ;-----------------------------------------------
  523. want_dollar_hex    lea    dollars_please,a0
  524.         bsr    print_error
  525.         bra    bail_out
  526. ;-----------------------------------------------
  527. bad_procnum    lea    dec_procnum,a0
  528.         bsr    print_error
  529.         bra    bail_out
  530. ;-----------------------------------------------
  531. give_syntax    lea    syntax,a0
  532.         bsr    print_error
  533.         bra    bail_out
  534. ;-----------------------------------------------
  535. cant_find_conf    lea    no_conf,a0
  536.         bsr    print_error
  537.         bra    bail_out
  538. ;-----------------------------------------------
  539. task_doesnt_exist
  540.         lea    bad_task,a0
  541.         bsr    print_error
  542.         bra    bail_out
  543. ;-----------------------------------------------
  544. proc_doesnt_exist
  545.         lea    bad_proc,a0
  546.         bsr    print_error
  547.         bra    bail_out
  548. ;-----------------------------------------------
  549. wrong_mode    lea    bad_trace_mode,a0
  550.         bsr    print_error
  551.         bra    bail_out
  552. ;-----------------------------------------------
  553. invalid_update_sp
  554.         lea    bad_speed,a0
  555.         bsr    print_error
  556.         bra    bail_out
  557. ;-----------------------------------------------
  558. cant_get_window    lea    win_too_big,a0
  559.         bsr    print_error
  560.         bra    bail_out
  561. ;-----------------------------------------------
  562. task_or_proc_please
  563.         lea    plonker,a0
  564.         bsr    print_error
  565.         bra    bail_out
  566. ;-----------------------------------------------
  567. need_020    lea    wrong_machine,a0
  568.         bsr    print_error
  569.         bra    bail_out
  570. ;-----------------------------------------------
  571. bad_conf_err    lea    bad_conf_file,a0
  572.         bsr    print_error
  573.         bra    bail_out
  574. ;-----------------------------------------------
  575. no_mem_for_descr
  576.         lea    no_descr_mem,a0
  577.         bsr    print_error
  578.         bra    bail_out
  579. ;-----------------------------------------------
  580. no_screen    lea    no_screen_str,a0
  581.         bsr    print_error
  582.         bra    bail_out
  583.  
  584. ;-----------------------------------------------
  585. ; Check our Window's IDCMP MessagePort for any Intuition events.
  586. ;-----------------------------------------------
  587.  
  588. handle_IDCMP
  589. while_msgs    move.l    4.w,a6
  590.         move.l    msgport,a0
  591.         EXEC    GetMsg            ;dequeue IntuiMessage.
  592.         tst.l    d0
  593.         req                ;if no event: exit
  594.  
  595.         move.l    d0,a1            ;A1 -> IntuiMessage
  596.         move.l    im_Class(a1),imsg_class    ;copy relevant message info
  597.         move.w    im_Code(a1),imsg_code
  598.         move.l    im_IAddress(a1),imsg_iaddr
  599.         move.l    im_MouseX(a1),imsg_ratcords    ;relative to window
  600.         EXEC    ReplyMsg        ;and return msg to Intuition
  601.  
  602.         move.l    imsg_class,d0        ;now find routine to execute
  603.         lea    event_routines,a0    ;for this event
  604.         bra    wh_msg_types
  605.  
  606. possible_event    move.l    (a0)+,a1        ;assuming this type: get vector
  607.         cmp.l    d0,d1            ;is this the event type we got ?
  608.         beq    handle_event        ;yes: go exec handler for this type.
  609.  
  610. wh_msg_types    move.l    (a0)+,d1        ;get possible event type
  611.         bpl    possible_event
  612.         bra    while_msgs
  613. ;---------------
  614. handle_event    jsr    (a1)            ;yes, process event
  615.         bra    while_msgs        ;any other events queued up?
  616.  
  617. ;=======================================================================
  618.         EVEN
  619. event_routines
  620. ;        dc.l    MOUSEMOVE,follow_mouse    ;when moving about in gadget
  621. ;        dc.l    GADGETDOWN,gadget_on    ;when first clicked
  622. ;        dc.l    MENUPICK,handle_menus    ;when selecting menu items
  623. ;        dc.l    RAWKEY,keypress        ;for value entry & arrow keys
  624.  
  625.         dc.l    GADGETUP,gadget_off    ;when released
  626.         dc.l    MOUSEBUTTONS,handle_click ;any clicks in Window
  627.         dc.l    CLOSEWINDOW,kill_program
  628.  
  629.         dc.l    -1            ;end of list
  630. ;=======================================================================
  631.  
  632. ;-----------------------------------------------
  633. ; User messed around with our slider gadget and finally released it.
  634. ; Read new knob position and adjust program update speed accordingly.
  635. ;-----------------------------------------------
  636.  
  637. gadget_off    lea    GadgetSInfo,a0        ;-> PropInfo struct for our slider
  638.  
  639.         moveq    #0,d0
  640.         move.w    pi_VertPot(a0),d0    ;get new pot setting    (0..64K)
  641.         moveq    #9,d1
  642.         lsr.w    d1,d0            ;scale it down a bit    (0..127)
  643.         move.l    d0,update_speed        ;max Delay() is 2.54 secs (127)
  644.         rts
  645. ;-----------------------------------------------
  646. ; Any click inside our window resets all counters (resets graphs to zero).
  647. ;-----------------------------------------------
  648. handle_click    move.w    imsg_code,d0        ;discard release clicks
  649.         and.w    #$0080,d0
  650.         rne
  651.  
  652.         move.l    counters,a0        ;-> array of LONG counters
  653.         moveq    #-1,d0
  654.         moveq    #0,d1
  655. reset_counters    move.l    d1,(a0)+        ;wipe all 65536 counters clean
  656.         dbra    d0,reset_counters
  657.  
  658. wipe_counters    move.l    GFX_LIB_PTR,a6
  659.         moveq    #0,d0            ;switch to background color for wipe
  660.         GFXR    SetAPen
  661.  
  662.         moveq    #PANE_X,d0        ;top-left corner for rectfill
  663.         moveq    #PANE_Y+2,d1
  664.         add.w    label_len,d0
  665.  
  666.         move.w    d0,d2            ;calc bot-right corner coords
  667.         move.w    d1,d3
  668.         add.w    #HEXNUM_SPACE-1,d2
  669.         add.w    contents_height,d3
  670.         add.w    #1,d3
  671.         GFXR    RectFill        ;wipe previous counters
  672.  
  673.         rts
  674. ;-----------------------------------------------
  675. kill_program    st    close_me        ;signal main loop to exit.
  676.         rts
  677.  
  678. ;-----------------------------------------------
  679. ; Analyse cached "ISAN.config" file.
  680. ; Validate format and create data structures for contents, the free file.
  681. ; Each line is either a comment line or a line with three comma-separated fields:
  682. ;    OPCODE,MASK,LABEL
  683. ;
  684. ; If argument flag "TOTAL" was present, add two special entries to show TOTAL
  685. ; number of instructions counted !!
  686. ;-----------------------------------------------
  687.  
  688. read_configuration
  689.         clr.w    opcodes            ;clr # of opcodes encountered
  690.         lea    count_opcodes,a5
  691.         bsr    scan_file        ;go through file and count opcode lines
  692.  
  693.         tst.l    total_flag        ;did user ask for automatic TOTAL too?
  694.         beq    get_descr_array
  695.         addq.w    #2,opcodes        ;make room for 2 more special entries
  696.  
  697. get_descr_array    move.l    4.w,a6
  698.         move.w    opcodes,d0        ;now allocate a memory block to hold
  699.         beq    bad_conf_err        ;exactly N Opcode descriptors structs
  700.  
  701.         mulu    #opc_sizeof,d0
  702.         move.l    d0,array_size
  703.         move.l    #MEMF_CLEAR|MEMF_PUBLIC,d1
  704.         EXEC    AllocMem
  705.         move.l    d0,opcode_list        ;opcode_list -> array to fill in.
  706.         beq    no_mem_for_descr
  707.  
  708.         moveq    #0,d7            ;max label length so far..
  709.  
  710.         move.l    opcode_list,a4        ;-> descriptor array to initialise
  711.         tst.l    total_flag        ;if total flag is set add our two
  712.         beq    fill_descriptors    ;special entries at the top of list
  713. ;---------------
  714.         moveq    #5,d7            ;max label length so far...
  715.  
  716.         move.w    #1,opc_combis(a4)
  717.         move.w    #SPECIAL1,opc_base_op(a4)  ;use an A-line opcode to signal
  718.         clr.w    opc_nocare_mask(a4)       ;special TOTAL "opcode"
  719.         move.l    #total_label,opc_label(a4) ;point to built-in label
  720.         move.w    d7,opc_label_len(a4)
  721.         add.l    #opc_sizeof,a4        ;point to next free slot
  722.  
  723.         move.w    #1,opc_combis(a4)       ;do a similar thing to get an
  724.         move.w    #SPECIAL2,opc_base_op(a4)  ;"underline" entry !
  725.         clr.w    opc_nocare_mask(a4)
  726.         move.l    #underline_label,opc_label(a4)
  727.         move.w    d7,opc_label_len(a4)
  728.         add.l    #opc_sizeof,a4        ;point to next free slot
  729. ;---------------
  730. fill_descriptors
  731.         lea    get_data,a5        ;go through file again but grab data
  732.         bsr    scan_file        ;to fill in descriptors.
  733.         bne    bad_conf_err
  734.  
  735.         mulu    #CHAR_WIDTH,d7        ;calc howmany width pixels labels
  736.         move.w    d7,label_len        ;will take up.
  737.  
  738.         move.w    opcodes,d0        ;calc howmany pixels high instruction
  739.         mulu    #CHAR_HEIGHT,d0        ;list will be
  740.         sub.w    #3,d0            ; - a bit to avoid wiping window edge
  741.         move.w    d0,contents_height
  742.  
  743.         add.w    #PANE_Y+8,d0        ;and automaticaly size
  744.         move.w    d0,win_h        ;window and
  745.         sub.w    #16,d0
  746.         move.w    d0,gad_h        ;attached slider gadget.
  747. ;---------------
  748.         rts
  749. ;-----------------------------------------------
  750. ; Go through cached ISAN.config file line-by-line and execute a user routine for
  751. ; every line starting with a "$".
  752. ; A4 -> Opcode descriptor array ptr
  753. ; A5 -> user routine to execute
  754. ; RETURNS (NE) if error occurred.
  755. ;-----------------------------------------------
  756. scan_file    move.l    conf_buffer,a0        ;-> cached ISAN.conf file
  757.  
  758.         bra    wh_lines
  759. ;---------------
  760. check_line    cmp.b    #'$',(a0)        ;instruction line ?
  761.         beq    handle_line        ;no, skip over entire line
  762.  
  763. skip_comment    move.b    (a0)+,d0
  764.         beq    file_eof
  765.         cmp.b    #LF,d0
  766.         bne    skip_comment
  767.         bra    wh_lines
  768. ;---------------
  769. handle_line    addq.w    #1,a0            ;skip "$"
  770.         jsr    (a5)            ;exec routine for a line starting w. $
  771.         bra    skip_comment
  772. ;---------------
  773. wh_lines    tst.b    (a0)            ;reached EOF yet ?
  774.         bne    check_line
  775. ;---------------
  776. file_eof    rts
  777.         
  778. ;-----------------------------------------------
  779. ; Initial user routine for scan_file to count opcode lines
  780. ;-----------------------------------------------
  781. count_opcodes    addq.w    #1,opcodes        ;just keep track of "$" lines
  782.         rts
  783. ;-----------------------------------------------
  784. ; Decode a $XXXX,$MMMM,"label" line
  785. ;
  786. ; A0 -> start of current line
  787. ; A4 -> next free Opcode descriptor slot
  788. ; D7 = maximum label length
  789. ;-----------------------------------------------
  790.  
  791. get_data    bsr    hex_to_bin        ;get basic opcode pattern
  792.         move.w    d0,opc_base_op(a4)
  793.  
  794.         cmp.b    #COMMA,(a0)+        ;need delimiter
  795.         bne    bad_conf_err
  796.         cmp.b    #'$',(a0)+        ;need hex number qualifier
  797.         bne    bad_conf_err
  798.  
  799.         bsr    hex_to_bin        ;get dont care mask
  800.         move.w    d0,opc_nocare_mask(a4)
  801.  
  802.         bsr    count_ones_in_D0    ;calc howmany opcode combinations
  803.         moveq    #0,d1            ;dont care mask means !
  804.         bset    d0,d1
  805.         move.w    d1,opc_combis(a4)
  806.  
  807.         cmp.b    #COMMA,(a0)+        ;need delimiter
  808.         bne    bad_conf_err
  809.         cmp.b    #DOUBLE_QUOTE,(a0)+    ;followed by start of string
  810.         bne    bad_conf_err
  811.     
  812.         move.l    a0,opc_label(a4)    ;store ptr to label string
  813.         move.l    a0,a1
  814.  
  815. calc_lab_len    cmp.b    #DOUBLE_QUOTE,(a1)+
  816.         bne    calc_lab_len        ;find end of label
  817.  
  818.         sub.l    opc_label(a4),a1    ;calc label length
  819.         sub.w    #1,a1
  820.         move.w    a1,opc_label_len(a4)
  821.  
  822.         cmp.w    d7,a1            ;label longer than all prev ones?
  823.         bcs    no_new_max
  824.         move.w    a1,d7            ;yes, update max length
  825. no_new_max    
  826.  
  827.         add.l    #opc_sizeof,a4        ;point to next free slot
  828.         rts
  829.  
  830. ;===================================================================================
  831. ; Go through opcode_list and stats array and generate list of opcode counters
  832. ; which we need to display.
  833. ; Find Maximum counter and scale all counters for clean display in window.
  834. ;
  835. ; LOOP REGISTERS:
  836. ;    D6 = maximum frequency so far
  837. ;    D7 = # of opcodes/groups to display
  838. ;    A4 -> current opcode descriptor
  839. ;    A5 -> base of counters array
  840. ;===================================================================================
  841.  
  842. scan_stats    move.l    4.w,a6            ;stop target Task (and all others!)
  843.         FORBID                ;so we can make consistent freq counts
  844.  
  845.         moveq    #0,d6            ;max freq so far
  846.         clr.l    most_frequent        ;clr ptr to slot of highest freq opc
  847.  
  848.         move.w    opcodes,d7        ;# of opcodes (groups) to scan
  849.         subq.w    #1,d7            ;-1 DBRA 
  850.         move.l    opcode_list,a4        ;-> array of opcode descriptors
  851.         move.l    counters,a5        ;-> 1 LONG for every 680x0 opcode!
  852.  
  853. ;---------------
  854. check_op_group    move.w    opc_combis(a4),d5    ;range of instructions or single ?
  855.         subq.w    #1,d5            ;(-1 DBRA)
  856.         bne    handle_range
  857.  
  858.         moveq    #0,d0            ;clear for LONG index !
  859.         move.w    opc_base_op(a4),d0    ;get opcode (all bits significant)
  860.         cmp.w    #SPECIAL1,d0
  861.         beq    calc_fast_total
  862.  
  863.         move.l    0(a5,d0.l*4),d1        ;get current cnt for this instruction
  864.         bra    update_max        ;join main flow again...
  865. ;---------------
  866. ; Here we go through counters array linearly and find total sum of instructions
  867. ; executed so far. This is faster than using the general purpose mask technique.
  868. ;---------------
  869. calc_fast_total    move.l    a5,a0
  870.         moveq    #0,d1            ;clear counter
  871.         move.w    #(65536/8)-1,d0        ;add up all 65536 LONG counters
  872. zap_through_it    add.l    (a0)+,d1        ;as quickly as possible...
  873.         add.l    (a0)+,d1
  874.         add.l    (a0)+,d1
  875.         add.l    (a0)+,d1
  876.         add.l    (a0)+,d1
  877.         add.l    (a0)+,d1
  878.         add.l    (a0)+,d1
  879.         add.l    (a0)+,d1
  880.         dbra    d0,zap_through_it
  881.  
  882. ;-- for TOTAL "opcode" we have a custom update_max which doesn't touch most_frequent
  883.         move.l    d1,opc_freq(a4)        ;remember locally
  884.         cmp.l    d6,d1            ;need to update maximum freq ?
  885.         bcs    next_opc
  886.         move.l    d1,d6            ;new max freq = current inst freq
  887.         bra    next_opc
  888.  
  889. ;---------------
  890. ; Here we have to generate ALL possible opcodes given the opcode template and
  891. ; the Don't Care bits mask.
  892. ; This isn't as straightforward as you might think.
  893. ;
  894. ; D7 = outer opcodes loop counter
  895. ; D6 = maximum frequency so far
  896. ; D5 = # of combinations in this opcode group
  897. ;---------------
  898.  
  899. handle_range    move.w    opc_nocare_mask(a4),d4    ;get dont care mask
  900.         move.w    opc_base_op(a4),d3    ;get opcode TEMPLATE
  901.  
  902.         move.w    d4,d2
  903.         not.w    d2            ;inverted dont care mask
  904.         and.w    d2,d3            ;d3 = 100% clean template mask
  905.  
  906. ; Say we have a dont care mask of $0E43. That's a mask with 3 bitfields that we
  907. ; should increment as if it were ONE contiguous bitfield.
  908. ; This is achieved by forcing all bits inbetween the bitfields to '1' and adding
  909. ; an "add mask" (the LSb '1' in the original mask); this way carry bits from a
  910. ; bitfield are transported across a 1s "bridge" to the next bitfield etc..
  911. ; The final opcode is derived from this "work" opcode and the original template by
  912. ; some ANDing and ORing.
  913.  
  914.         move.w    d4,d0            ;original don't care mask
  915.         moveq    #-1,d1            ;calc the "add mask"
  916. find_first_lsb    addq.w    #1,d1            ;(= the lowest 1 bit in the mask on
  917.         lsr.w    #1,d0            ;its own).
  918.         bcc    find_first_lsb
  919.         moveq    #0,d0
  920.         bset    d1,d0            ;D0 is add mask.
  921.  
  922.         sub.l    a0,a0            ;clr accumulated freq of opc family
  923.         moveq    #0,d1            ;FOR CNT=0 TO COMBI-1
  924. ;--------
  925. gen_codes    and.w    d4,d1            ;mask out "scattered count"
  926.         or.w    d3,d1            ;or in clean template = final opcode
  927.  
  928.         add.l    0(a5,d1.l*4),a0        ;add its freq to total group freq
  929.  
  930.         or.w    d2,d1            ;0 holes = bitfields
  931.         add.w    d0,d1            ;"add" across bitfield voids
  932.  
  933.         dbra    d5,gen_codes        ;all possible combinations generated?
  934.  
  935.         move.l    a0,d1            ;sum total of opcode group
  936. ;---------------
  937. update_max    move.l    d1,opc_freq(a4)        ;total # of ops of this type counted
  938.         cmp.l    d6,d1            ;need to update maximum freq ?
  939.         bcs    next_opc
  940.  
  941.         move.l    d1,d6            ;new max freq = current inst freq
  942.         move.l    a4,most_frequent    ;remember most freq opc slot
  943. ;---------------
  944. next_opc    add.l    #opc_sizeof,a4        ;goto next descriptor
  945.         dbra    d7,check_op_group    ;all done ?
  946.  
  947. ;-----------------------------
  948. ; We've gone through all opcodes we want to snoop on.
  949. ; From the found maximum frequency normalize all frequencies so that max = $FFFFFFFF
  950. ;-----------------------------
  951.  
  952.         or.b    #1,d6            ;force max freq to have at least one 1 bit
  953.         bfffo    d6{0:32},d0        ;find # of LEFT shifts to normalize max
  954.  
  955.         move.w    opcodes,d7        ;# of opcodes (groups) to scan
  956.         subq.w    #1,d7            ;-1 DBRA 
  957.         move.l    opcode_list,a4        ;-> array of opcode descriptors
  958.  
  959. norm_counts    move.l    opc_freq(a4),d1        ;get original frequency
  960.         lsl.l    d0,d1            ;normalize it
  961.         move.l    d1,opc_xfreq(a4)    ;store normalized frequency
  962.  
  963.         add.l    #opc_sizeof,a4        ;goto next descriptor
  964.         dbra    d7,norm_counts        ;all done ?
  965.  
  966.         move.l    4.w,a6            ;thanks for hanging around guys...!
  967.         PERMIT                ;carry on now..
  968.     
  969.         rts
  970. ;-----------------------------------------------
  971. ; Redraw ENTIRE contents of Window.    (**!! Should optimize)
  972. ;-----------------------------------------------
  973. update_windows    bsr    update_op_counters
  974.         bsr    update_registers
  975.         bsr    update_PC_counters
  976.         rts
  977. ;-----------------------------------------------
  978. ; Update the main statistics window containing opcode usage frequencies.
  979. ;-----------------------------------------------
  980. update_op_counters
  981.         move.l    GFX_LIB_PTR,a6        ;using graphics.library...
  982.         moveq    #1,d0            ;set color for labels & hex frequencies
  983.         GFXR    SetAPen
  984.  
  985.         moveq    #PANE_X,d5        ;initial cursor coords.
  986.         moveq    #PANE_Y+CHAR_HEIGHT,d6
  987.  
  988.         move.w    opcodes,d7        ;# of graphs/labels to draw
  989.         subq.w    #1,d7
  990.         move.l    opcode_list,a4        ;-> array of opcode descriptors
  991. ;---------------
  992. draw_labels    tst.b    add_labels        ;have labels already been printed ?
  993.         beq    skip_labels        ;yes, don't print again (since static)
  994.  
  995.         move.w    d5,d0
  996.         move.w    d6,d1
  997.         GFXR    Move            ;set text cursor for label
  998.  
  999.         move.l    opc_label(a4),a0
  1000.         move.w    opc_label_len(a4),d0
  1001.         GFXR    Text            ;print label
  1002.  
  1003. skip_labels    move.l    opc_freq(a4),d0        ;create hex string from freq.
  1004.         beq    zero_cnt        ;if freq is zero then just print "0"
  1005.  
  1006.         moveq    #8,d1            ;otherwise print hex number as eight
  1007.         lea    hex_output,a0        ;full digits
  1008.         bsr    bin_hex
  1009.  
  1010.         move.w    d5,d0
  1011.         move.w    d6,d1
  1012.         add.w    label_len,d0        ;just after labels...
  1013.         GFXR    Move            ;set cursor for frequency
  1014.  
  1015.         moveq    #8,d0
  1016.         lea    hex_output,a0
  1017.         GFXR    Text            ;print hex frequency 'xxxxxxxx'
  1018.         bra    do_labels
  1019. ;--------
  1020. zero_cnt    move.w    d5,d0
  1021.         move.w    d6,d1
  1022.         add.w    label_len,d0        ;just after labels...
  1023.         add.w    #7*CHAR_WIDTH,d0    ;(strip leading zeros)
  1024.         GFXR    Move            ;set cursor for frequency
  1025.  
  1026.         moveq    #1,d0
  1027.         lea    a_zero,a0
  1028.         GFXR    Text            ;print hex frequency '       0'
  1029.  
  1030. do_labels    add.w    #CHAR_HEIGHT,d6        ;down one line
  1031.         add.l    #opc_sizeof,a4        ;goto next descriptor
  1032.         dbra    d7,draw_labels
  1033.  
  1034.         sf    add_labels        ;from now: never draw labels again
  1035. ;---------------
  1036. wipe_graph_area    moveq    #0,d0            ;switch to background color for wipe
  1037.         GFXR    SetAPen
  1038.  
  1039.         moveq    #PANE_X+HEXNUM_SPACE,d0    ;top-left corner for rectfill
  1040.         add.w    label_len,d0
  1041.         moveq    #PANE_Y+3,d1
  1042.  
  1043.         moveq    #PANE_X,d2        ;calc bot-right corner coords
  1044.         add.w    win_width,d2
  1045.         sub.w    #GADG_WIDTH,d2
  1046.         move.w    contents_height,d3
  1047.         add.w    d1,d3
  1048.         GFXR    RectFill        ;wipe previous graphs display
  1049. ;---------------
  1050.         moveq    #0,d0
  1051.         move.w    win_width,d0        ;total window width
  1052.         sub.w    label_len,d0        ;- area where labels go
  1053.         sub.w    #PANE_X+HEXNUM_SPACE+5,d0 ;= available drawing length
  1054.  
  1055.         bfffo    d0{0:32},d4        ;calc window width scale factor
  1056.         addq.w    #1,d4
  1057. ;---------------
  1058.         moveq    #PANE_Y+4,d6
  1059.         moveq    #PANE_X+HEXNUM_SPACE,d5    ;initial pen X,Y
  1060.         add.w    label_len,d5
  1061.         add.w    #2,d5
  1062.  
  1063.         move.w    opcodes,d7        ;# of graphs/labels to draw
  1064.         subq.w    #1,d7
  1065.         move.l    opcode_list,a4        ;-> array of opcode descriptors
  1066.  
  1067. draw_graph    tst.l    opc_xfreq(a4)        ;any graph to draw at all ??
  1068.         beq    skip_graph        ;yes, (freq non-zero)
  1069.  
  1070.         moveq    #2,d0            ;assume normal graph color
  1071.         cmp.l    most_frequent,a4    ;does this slot represent max freq?
  1072.         bne    draw_line        ;yes,
  1073.  
  1074.         moveq    #1,d0            ;highlight longest opcode graph
  1075.  
  1076. draw_line    GFXR    SetAPen            ;select color for graph
  1077.  
  1078.         move.w    d5,d0
  1079.         move.w    d6,d1
  1080.         GFXR    Move            ;Move to start of line
  1081.  
  1082.         move.l    opc_xfreq(a4),d0    ;get LONG normalized inst. freq.
  1083.         lsr.l    d4,d0            ;scale to fit window
  1084.         add.w    d5,d0            ;add positioning offset
  1085.         move.w    d6,d1
  1086.         GFXR    Draw            ;draw a bargraph line
  1087.  
  1088. skip_graph    add.w    #CHAR_HEIGHT,d6        ;down one line
  1089.         add.l    #opc_sizeof,a4        ;goto next descriptor
  1090.         dbra    d7,draw_graph
  1091.         rts
  1092. ;-----------------------------------------------
  1093. ;-- Now optionally dump all registers in REGISTER window
  1094. ;-----------------------------------------------
  1095. update_registers
  1096.         tst.l    regswin_rp        ;if no register window: don't
  1097.         req
  1098.  
  1099.         lea    regs_dump,a3        ;-> 16 registers to display
  1100.  
  1101.         moveq    #4-1,d7            ;print 4 lines of 4 registers
  1102.         moveq    #PANE_Y+CHAR_HEIGHT,d4
  1103.  
  1104. print_regline    moveq    #4-1,d6
  1105.         moveq    #PANE_X+3*CHAR_WIDTH,d3    ;reset cursor X
  1106.  
  1107. print_reg    move.l    regswin_rp,a1
  1108.         move.w    d3,d0
  1109.         move.w    d4,d1
  1110.         GFX    Move
  1111.  
  1112.         move.l    (a3)+,d0        ;get a register value
  1113.         moveq    #8,d1
  1114.         lea    hex_output,a0
  1115.         bsr    bin_hex            ;convert to ASCII string
  1116.  
  1117.         moveq    #8,d0
  1118.         lea    hex_output,a0
  1119.         move.l    regswin_rp,a1
  1120.         GFX    Text
  1121.  
  1122.         add.w    #12*CHAR_WIDTH,d3
  1123.         dbra    d6,print_reg
  1124.     
  1125.         add.w    #CHAR_HEIGHT,d4
  1126.         dbra    d7,print_regline
  1127. ;---------------
  1128.         move.l    (a3)+,d0        ;get PC register value
  1129.         moveq    #8,d1
  1130.         lea    hex_output,a0
  1131.         bsr    bin_hex            ;convert to ASCII string
  1132.  
  1133.         move.l    regswin_rp,a1
  1134.         moveq    #PANE_X+3*CHAR_WIDTH,d0    ;reset cursor X
  1135.         move.w    d4,d1
  1136.         GFX    Move
  1137.  
  1138.         moveq    #8,d0
  1139.         lea    hex_output,a0
  1140.         move.l    regswin_rp,a1
  1141.         GFX    Text            ;"PC=XXXXXXXX"
  1142.         rts
  1143. ;-----------------------------------------------
  1144. ; Optionally update PC counters in PC PROFILE window.
  1145. ;-----------------------------------------------
  1146. update_PC_counters
  1147.         tst.l    profwin_rp        ;if no register window: don't
  1148.         req
  1149.  
  1150.         tst.w    num_PCs            ;if any PCs trapped yet...
  1151.         req
  1152.  
  1153.         move.l    PC_history_PCs,a3    ;-> N PC statistics to display
  1154.         move.l    PC_history_cnts,a4    ;->
  1155.  
  1156.         moveq    #0,d7            ;print N lines ...
  1157.  
  1158. print_PC_line    moveq    #0,d0
  1159.         move.w    d7,d0            ;list grows like newspaper columns
  1160.         divu    #42,d0
  1161.         move.l    d0,d1            ;save quotient
  1162.         swap    d0            ;get remainder down
  1163.         mulu    #CHAR_HEIGHT,d0
  1164.         add.w    #PANE_Y+CHAR_HEIGHT,d0
  1165.  
  1166.         mulu    #20*CHAR_WIDTH,d1
  1167.         add.w    #PANE_X,d1
  1168.  
  1169.         exg    d0,d1            ;AARRGGHHH !!
  1170.  
  1171.         move.w    d0,d3
  1172.         move.w    d1,d4
  1173.  
  1174.         move.l    profwin_rp,a1
  1175.         GFX    Move
  1176.  
  1177.         move.l    (a3),d0            ;get a PC register value
  1178.         moveq    #8,d1
  1179.         lea    hex_output,a0
  1180.         bsr    bin_hex            ;convert to ASCII string
  1181.  
  1182.         moveq    #8,d0
  1183.         lea    hex_output,a0
  1184.         move.l    profwin_rp,a1
  1185.         GFX    Text
  1186. ;------
  1187. just_print_cnt    move.w    d3,d0
  1188.         add.w    #10*CHAR_WIDTH,d0
  1189.         move.w    d4,d1
  1190.         move.l    profwin_rp,a1
  1191.         GFX    Move
  1192.  
  1193.         move.l    #'    ',hex_output
  1194.         move.l    #'   0',hex_output+4
  1195.         move.l    (a4)+,d0        ;get # of times PC got here (counter)
  1196.         moveq    #8,d1
  1197.         lea    hex_output,a0
  1198.         bsr    bin_hex            ;convert to ASCII string
  1199.  
  1200.         moveq    #8,d0
  1201.         lea    hex_output,a0
  1202.         move.l    profwin_rp,a1
  1203.         GFX    Text
  1204.  
  1205.         addq.w    #4,a3            ;-> next PC value
  1206.         addq.w    #1,d7
  1207.         cmp.w    num_PCs,d7        ;done entire list ?
  1208.         bne    print_PC_line
  1209.  
  1210.         rts
  1211. ;-----------------------------------------------
  1212. ; Go through counters array and plot a pixel in the map screen for every non-zero
  1213. ; counter.
  1214. ; We don't use a pixel plot routine (much too slow), instead we check 32 opcodes
  1215. ; in one go, creating a bunch of 32 pixels in a data reg and then we write this
  1216. ; to the screen.
  1217. ;-----------------------------------------------
  1218.  
  1219. LINE_SIZE    equ    32            ;bytes for a 256 pixels line
  1220.  
  1221. update_screen    tst.l    opcode_map        ;is screen enabled ?
  1222.         req                ;yep,
  1223.  
  1224.         move.l    map_screen,a1
  1225.         lea    sc_BitMap+bm_Planes(a1),a1
  1226.         move.l    (a1),a1            ;get bitplane 0 ptr
  1227.         add.l    #12*LINE_SIZE,a1    ;skip Screen Title/Dragbar area.
  1228.  
  1229.         move.l    counters,a0        ;get base address of counters array
  1230.         move.w    #(65536/32)-1,d7    ;check all opcodes in blocks of 32
  1231.  
  1232. plot_counters    moveq    #32-1,d1        ;construct 32 pixels in register
  1233.         moveq    #0,d0            ;clear pixel line LONG
  1234.  
  1235. constr_pixline    tst.l    (a0)+            ;opcode used at all ?
  1236.         beq    unused_opcode        ;yes,
  1237.         bset    d1,d0            ;set its pixel (use DBRA counter as bit #)
  1238.  
  1239. unused_opcode    dbra    d1,constr_pixline
  1240.  
  1241.         move.l    d0,(a1)+        ;blast 32 pixels into screen at a time
  1242.         dbra    d7,plot_counters
  1243.         rts
  1244. ;-----------------------------------------------
  1245. ; Set all program parameters to defaults before parsing argument line.
  1246. ;-----------------------------------------------
  1247.  
  1248. clear_results    clr.l    task_arg        ;
  1249.         clr.l    process_arg        ;
  1250.  
  1251.         move.l    #twenty,update_speed    ;DOS Delay() factor
  1252.         move.l    #one,trace_mode        ;default TRACE mode = 1
  1253.  
  1254.         clr.l    total_flag        ;don't add total counter !
  1255.         clr.l    profile_flag        ;don't use profiling
  1256.  
  1257.         move.w    #WINDOW_WIDTH,win_width    
  1258.  
  1259.         move.l    #default_conf,conf_file
  1260.  
  1261. dummy        rts
  1262.  
  1263. ;-----------------------------------------------
  1264. ; Validate user's Process ID.
  1265. ; Return EQ if Task exists
  1266. ;
  1267. ; IN : D7.L = Process #
  1268. ;
  1269. ; OUT: D2.L = Process TCB addr or NULL
  1270. ;-----------------------------------------------
  1271.  
  1272. check_process    move.l    4.w,a6            ;-> Exec Library
  1273.  
  1274.         DISABLE                ;no list altering while we look!
  1275.         lea    TaskWait(a6),a5        ;scan TaskWait list first (most likely)
  1276.         bsr    find_process
  1277.         bne    is_process
  1278.  
  1279.         lea    TaskReady(a6),a5    ;if not on Wait list, maybe on Ready
  1280.         bsr    find_process
  1281.  
  1282. is_process    ENABLE
  1283.         rts
  1284. ;-----------------------------------------------
  1285. ; Try to find Process N on given Task list
  1286. ; A5 -> List Head
  1287. ; D7.L = Process number
  1288. ;-----------------------------------------------
  1289. find_process    move.l    (a5),d1            ;get head of list
  1290.         beq    plist_end
  1291.  
  1292.         move.l    d1,a5            ;move LN_SUCC to curr Node ptr
  1293.  
  1294.         cmp.b    #NT_PROCESS,LN_TYPE(a5)    ;is this a Process ?
  1295.         bne    find_process        ;no, goto next Task
  1296.  
  1297.         cmp.l    pr_TaskNum(a5),d7    ;ok, is this the Process we want ?
  1298.         bne    find_process
  1299.  
  1300.         move.l    a5,d2            ;yes: return tcb addr.
  1301.         rts
  1302. ;---------------
  1303. plist_end    moveq    #0,d2            ;didn't find Process (return NULL)
  1304.         rts
  1305. ;-----------------------------------------------
  1306. ; Validate user's TASK address.
  1307. ; Return EQ if Task exists
  1308. ;-----------------------------------------------
  1309.  
  1310. check_taskaddr    move.l    4.w,a6            ;-> Exec Library
  1311.         move.l    tcb_ptr,a0        ;find Task node with this start adr
  1312.  
  1313.         DISABLE                ;no list altering while we look!
  1314.         move.l    TaskWait(a6),a5        ;scan TaskWait list first (most likely)
  1315.         bsr    find_task
  1316.         beq    is_task
  1317.  
  1318.         move.l    TaskReady(a6),a5    ;maybe a CPU hog then ?
  1319.         bsr    find_task
  1320.         beq    is_task
  1321.  
  1322.         ENABLE
  1323.         moveq    #-1,d0            ;NE = nope, couldn't find Task
  1324.         rts
  1325.  
  1326. is_task        ENABLE
  1327.         moveq    #0,d0            ;EQ = yep, found Task
  1328.         rts
  1329. ;-----------------------------------------------
  1330. ; Try to find Task X on given Task list
  1331. ; A5 -> List Head
  1332. ; A0 -> Task addr
  1333. ;-----------------------------------------------
  1334. find_task    tst.l    (a5)            ;is this node the Tail of list ?
  1335.         beq    list_tail        ;nope.
  1336.  
  1337.         cmp.l    a5,a0            ;check against user input
  1338.         beq    task_present        ;if match return EQ
  1339.  
  1340.         move.l    (a5),a5
  1341.         bra    find_task
  1342.  
  1343. list_tail    moveq    #-1,d0            ;else NE
  1344. task_present    rts
  1345. ;-----------------------------------------------
  1346. ; Modify the target Task's trace bits in its SR (stored in its saved context).
  1347. ; Point its TC_TRAP vectors to our stuff to handle all those TRACE exceptions.
  1348. ;-----------------------------------------------
  1349.  
  1350. start_task_traceing
  1351.         move.l    tcb_ptr,a5        ;-> Task/Process to snoop on.
  1352.  
  1353.         move.l    counters,TC_TRAPDATA(a5)    ;tell handler where counters are
  1354.         move.l    TC_TRAPCODE(a5),old_trapcode    ;save any old trap handlers
  1355.  
  1356.         lea    default_handler,a0    ;choose which trace handler to use
  1357.  
  1358.         tst.l    profile_flag
  1359.         beq    use_regs_maybe
  1360.  
  1361.         lea    proftrace_handler,a0
  1362.         bra    curse_task
  1363.  
  1364. use_regs_maybe    tst.l    show_regs
  1365.         beq    curse_task
  1366.         lea    rgtrace_handler,a0
  1367.  
  1368. curse_task    move.l    a0,TC_TRAPCODE(a5)    ;install our TRACE handler
  1369.  
  1370.         move.b    #$80,d0            ;assume normal TRACE mode (T1=1,T0=0)
  1371.         tst.l    trace_mode
  1372.         beq    normal_trace
  1373.         move.b    #$40,d0            ;T1=0, T0=0
  1374.  
  1375. normal_trace    move.l    4.w,a6
  1376.         DISABLE
  1377.         move.l    TC_SPREG(a5),a1        ;find Task's saved context
  1378.         and.b    #$3F,8(a1)        ;clear any trace bits already set.
  1379.         or.b    d0,8(a1)        ;go set TRACE bits in saved SR reg !
  1380.         ENABLE
  1381.         rts
  1382. ;-----------------------------------------------
  1383. ; We've got enough info on traced Task. Switch it back to normal mode.
  1384. ; **!! This doesn't check whether the Task is still actually there or not !
  1385. ;-----------------------------------------------
  1386.  
  1387. stop_task_traceing
  1388.         move.l    tcb_ptr,a5        ;get Task's TCB address
  1389.  
  1390.         move.l    4.w,a6            ;using Exec..
  1391.         DISABLE                ;freeze multi-tasking while modifying
  1392.  
  1393. ;**!!        move.l    old_trapcode,TC_TRAPCODE(a5)    ;restore original handler
  1394. ;        clr.l    TC_TRAPDATA(a5)
  1395.  
  1396.         move.l    TC_SPREG(a5),a1        ;find Task's saved context
  1397.         and.b    #$3F,8(a1)        ;clear T1, T0
  1398.         ENABLE
  1399.         rts
  1400.  
  1401. ;------------------------------------------------------------------------------------
  1402. ; This EXCEPTION handler is executed after EVERY instruction of the
  1403. ; target Task/Process once we switched "its" CPU into TRACE mode.
  1404. ;
  1405. ; ** THIS IS EFFECTIVELY THE CORE OF THE ENTIRE PROGRAM **
  1406. ;
  1407. ;------------------------------------------------------------------------------------
  1408.  
  1409.  
  1410. REGS_SAVED1    equ    2            ;size of "stack frame"
  1411.  
  1412.  
  1413. default_handler:
  1414.         addq.l    #4,SP            ;discard garbage that Exec added.
  1415.  
  1416.         move.l    a0,-(sp)        ;handler has to be transparent (like IRQ)
  1417.         move.l    d0,-(sp)        ;(2 * move is faster than movem)
  1418.  
  1419.         move.l    ([4]ThisTask),a0    ;find address of Task that trapped
  1420.         move.l    TC_TRAPDATA(a0),a0    ;get ptr to array of LONG counters
  1421.  
  1422.         moveq    #0,d0            ;clear MSW for following casting...
  1423.         move.w    ([sp,8+REGS_SAVED1*4]),d0  ;get opcode (cast to LONG)
  1424.         addq.l    #1,0(a0,d0.l*4)        ;increment this opcode's counter
  1425.  
  1426.         move.l    (sp)+,d0        ;restore used registers
  1427.         move.l    (sp)+,a0
  1428.  
  1429.         rte    ;ret to Task for just ONE instruction and come back here !
  1430. ;-----------------------------------------------
  1431. ;**!! The original trace handler used to use conservative 68000 addressing modes
  1432. ;**!! By using the new 68020+ modes we're able to use one address register less
  1433. ;**!! than before which in turns means less to save/restore.
  1434.  
  1435. ; The old code looked like this:
  1436.  
  1437. ;        move.l    4.w,a0            ;find address of Task that trapped.
  1438. ;        move.l    ThisTask(a0),a0
  1439. ;        move.l    TC_TRAPDATA(a0),a1    ;get ptr to array of LONG counters
  1440.  
  1441. ;        move.l    8+12(sp),a0        ;get address of opcode that trapped
  1442. ;        move.w    (a0),d0            ;get opcode
  1443.  
  1444. ;-----------------------------------------------
  1445. ; This is an alternative (slower) handler that also dumps all 680x0 registers.
  1446. ; This handler is only used when the user specifies the REGS option.
  1447. ;-----------------------------------------------
  1448.  
  1449. REGS_SAVED2    equ    2
  1450.  
  1451.  
  1452. rgtrace_handler:addq.l    #4,SP
  1453.  
  1454.         movem.l    d0-d7/a0-a6,regs_dump    ;dump all Dn/An registers
  1455.         move.l    8(sp),regs_dump+16*4    ;and PC
  1456. ;---------------
  1457.         move.l    a0,-(sp)
  1458.         move.l    d0,-(sp)
  1459.  
  1460.         move.l    USP,a0
  1461.         move.l    a0,regs_dump+15*4
  1462.  
  1463.         move.l    ([4]ThisTask),a0
  1464.         move.l    TC_TRAPDATA(a0),a0
  1465.  
  1466.         moveq    #0,d0
  1467.         move.w    ([sp,8+REGS_SAVED2*4]),d0
  1468.         addq.l    #1,0(a0,d0.l*4)
  1469.  
  1470.         move.l    (sp)+,d0
  1471.         move.l    (sp)+,a0
  1472.         rte
  1473. ;-----------------------------------------------
  1474. ; This is another alternative handler which also some PC register statistics.
  1475. ; This handler is only used when the user specifies the PROFILE option.
  1476. ;-----------------------------------------------
  1477.  
  1478. REGS_SAVED3    equ    4
  1479.  
  1480. proftrace_handler:
  1481.         addq.l    #4,SP
  1482.  
  1483.         movem.l    d0-d7/a0-a6,regs_dump    ;dump all Dn/An registers
  1484.         move.l    8(sp),regs_dump+16*4    ;and PC
  1485. ;---------------
  1486.         movem.l    d0-d1/a0-a1,-(sp)
  1487.  
  1488.         move.l    USP,a0
  1489.         move.l    a0,regs_dump+15*4
  1490.  
  1491.         move.l    ([4]ThisTask),a0
  1492.         move.l    TC_TRAPDATA(a0),a0
  1493.  
  1494.         moveq    #0,d0
  1495.         move.w    ([sp,8+REGS_SAVED3*4]),d0
  1496.         addq.l    #1,0(a0,d0.l*4)
  1497.  
  1498.         move.l    regs_dump+16*4,d0
  1499.         cmp.l    #$00F80000,d0
  1500.         bcs    non_ROM_PC
  1501.         cmp.l    #$01000000,d0
  1502.         bcs    skip_ROM_PC
  1503.  
  1504. non_ROM_PC    bsr    update_PC_hist
  1505.  
  1506. skip_ROM_PC    movem.l    (sp)+,d0-d1/a0-a1
  1507.         rte
  1508. ;-----------------------------------------------
  1509. ; Go through PC History array and update/add
  1510. ; a PC entry.
  1511. ;-----------------------------------------------
  1512. update_PC_hist    move.l    PC_history_PCs,a0    ;-> N PC values followed by N counters
  1513.         move.l    regs_dump+16*4,d1    ;get PC value of TRACE exception
  1514.  
  1515.         move.w    num_PCs,d0        ;how long is list to check ?
  1516.         beq    add_new_PC
  1517.  
  1518.         subq.w    #1,d0
  1519.  
  1520. check_history    cmp.l    (a0)+,d1        ;does this PC already occur in list?
  1521.         dbeq    d0,check_history
  1522.         bne    add_new_PC
  1523.  
  1524. inc_PC_counter    add.l    #(MAX_PC_HIST*4)-4,a0
  1525.         addq.l    #1,(a0)            ;yes, just incr. its counter
  1526.         rts
  1527.  
  1528. add_new_PC    cmp.w    #MAX_PC_HIST,num_PCs    ;stop storing new ones when full
  1529.         rcc
  1530.  
  1531.         move.l    PC_history_PCs,a0    ;otherwise
  1532.         move.l    PC_history_cnts,a1
  1533.  
  1534.         move.w    num_PCs,d0    
  1535.         move.l    d1,(a0,d0*4)        ;add new PC to list
  1536.         moveq    #1,d1
  1537.         move.l    d1,(a1,d0*4)        ;& init its counter
  1538.  
  1539.         addq.w    #1,num_PCs        ;keep track of size of list
  1540.         rts
  1541. ;-----------------------------------------------
  1542. ; Initialize some variables
  1543. ;-----------------------------------------------
  1544. init_isan    clr.l    window            ;clr ptrs to ensure safe freeing
  1545.         clr.l    regs_window        ;in case of allocation failure
  1546.         clr.l    prof_window
  1547.  
  1548.         clr.l    map_screen
  1549.         clr.l    font_ptr
  1550.  
  1551.         clr.l    PC_history_PCs
  1552.         clr.l    opcode_list
  1553.  
  1554.         clr.w    num_PCs            ;no PCs so far.
  1555.  
  1556.         sf    close_me        ;no need to quit just now...
  1557.         st    add_labels        ;first update pass we want labels
  1558.  
  1559.         rts
  1560. ;-----------------------------------------------
  1561. ; Open Dos, Graphics and Intuition libraries.
  1562. ;-----------------------------------------------
  1563. open_libs    move.l    4.w,a6            ;using Exec..
  1564.         lea    dosname,a1
  1565.         moveq    #0,d0
  1566.         EXEC    OpenLibrary        ;open DOS
  1567.         move.l    d0,DOS_LIB_PTR
  1568.         beq    beg_your_pardon
  1569.  
  1570.         lea    gfxname,a1
  1571.         moveq    #0,d0
  1572.         EXEC    OpenLibrary
  1573.         move.l    d0,GFX_LIB_PTR        ;open GFX
  1574.         beq    beg_your_pardon
  1575.  
  1576.         lea    intuiname,a1
  1577.         moveq    #0,d0
  1578.         EXEC    OpenLibrary        ;open Intuition
  1579.         move.l    d0,INTUI_LIB_PTR
  1580.  
  1581.         move.l    DOS_LIB_PTR,a6        ;and using DOS
  1582.         DOS    Output            ;get standard output filehandle
  1583.         move.l    d0,stdout
  1584.  
  1585. beg_your_pardon    rts
  1586. ;-----------------------------------------------
  1587. close_libs    move.l    4.w,a6            ;using Exec..
  1588.         move.l    DOS_LIB_PTR,d0
  1589.         beq    no_dos
  1590.         move.l    d0,a1
  1591.         EXEC    CloseLibrary        ;close DOS
  1592.  
  1593. no_dos        move.l    GFX_LIB_PTR,d0
  1594.         beq    no_gfx
  1595.         move.l    d0,a1
  1596.         EXEC    CloseLibrary        ;close GFX
  1597.  
  1598. no_gfx        move.l    INTUI_LIB_PTR,d0
  1599.         beq    done_lib_closures
  1600.         move.l    d0,a1
  1601.         EXEC    CloseLibrary        ;close Intuition
  1602. done_lib_closures
  1603.         rts
  1604. ;-----------------------------------------------
  1605. ; Convert hex string pointed to by A0 into binary.
  1606. ; Return in D0.L
  1607. ;-----------------------------------------------
  1608. hex_to_bin    moveq    #0,d0            ;clear accumulator
  1609.         bra    wh_nibbles
  1610.  
  1611. add_nibble    lsl.l    #4,d0
  1612.         add.b    d1,d0
  1613.  
  1614. wh_nibbles    moveq    #0,d1            ;(clear high byte of index reg)
  1615.         move.b    (a0)+,d1        ;get char
  1616.  
  1617.         sub.b    #'0',d1            ;make sure char is in set of legal
  1618.         bcs    not_hex            ;hex chars
  1619.         cmp.b    #'f'-'0',d1
  1620.         bhi    not_hex
  1621.  
  1622.         move.b    h2bin(PC,d1.w),d1    ;use char as index into lookup table
  1623.         bpl    add_nibble        ;if lookup gives valid nibble
  1624. ;---------------
  1625. not_hex        subq.w    #1,a0            ;backtrack to first non-hex char
  1626.         rts
  1627.  
  1628. h2bin        dc.b    0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1
  1629.         dc.b    -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1    ;@..'O'
  1630.         dc.b    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1    ;'P'.._
  1631.         dc.b    -1,10,11,12,13,14,15
  1632. ;-----------------------------------------------
  1633. ; Count number of '1' bits in D0.L
  1634. ; Return in D0.L
  1635. ;-----------------------------------------------
  1636.         EVEN
  1637. count_ones_in_D0
  1638.         moveq    #0,d1            ;zero count.
  1639.         moveq    #0,d2            ;dummy addition operand for ADDX
  1640.  
  1641. count_ones    add.l    d0,d0            ;shift a '0' or a '1' out in Carry
  1642.         addx.l    d2,d1            ;add 1 to count if C=1
  1643.         tst.l    d0
  1644.         bne    count_ones
  1645.  
  1646. found_all_ones    move.w    d1,d0
  1647.         rts
  1648.  
  1649. ;-----------------------------------------------
  1650. ; Leading Zero stripped BIN_HEX
  1651. ;-----------------------------------------------
  1652. bin_hex        move.l    a0,-(sp)
  1653.         move.l    d1,-(sp)
  1654.         bsr    BIN_HEX
  1655.         move.l    (sp)+,d1
  1656.         move.l    (sp)+,a0
  1657.  
  1658.         subq.w    #2,d1            ;-2 to leave at least 1 '0'
  1659. kill_leading_0    cmp.b    #'0',(a0)
  1660.         rne
  1661.         move.b    #' ',(a0)+
  1662.         dbra    d1,kill_leading_0
  1663.         rts
  1664. ;-----------------------------------------------
  1665. ; Here I IMPORT some handy MODULES
  1666. ;-----------------------------------------------
  1667.         include    SRC:UTILS/ReadArgs.s    ;argline parser (with std template)
  1668.         include    SRC:UTILS/load_file.s    ;entire file loader
  1669.         include SRC:MODULES/LIB1/BIN_HEX
  1670.         include    SRC:MODULES/LIB1/DEC_TO_BIN
  1671. ;-----------------------------------------------
  1672.         EVEN
  1673.  
  1674. MyNewWindow:
  1675.     dc.w    640-WINDOW_WIDTH-13    ;window XY origin relative to TopLeft of screen
  1676.     dc.w    0
  1677.     dc.w    WINDOW_WIDTH+13        ;window width and
  1678. win_h    dc.w    131            ;height (FILLED IN)
  1679.     dc.b    0,1            ;detail and block pens
  1680.  
  1681. ;IDCMP flags
  1682.     dc.l    CLOSEWINDOW+GADGETUP+MOUSEBUTTONS
  1683.  
  1684. ;Window flags
  1685.     dc.l    WINDOWDRAG+WINDOWDEPTH+WINDOWCLOSE+ACTIVATE+NOCAREREFRESH+REPORTMOUSE
  1686.  
  1687.     dc.l    Gadgets            ;first gadget in gadget list
  1688.     dc.l    NULL            ;custom CHECKMARK imagery
  1689.     dc.l    WindowName        ;window title
  1690.     dc.l    NULL            ;custom screen pointer
  1691.     dc.l    NULL            ;custom bitmap
  1692.     dc.w    5,5            ;minimum width and height
  1693.     dc.w    -1,-1            ;maximum width and height
  1694.     dc.w    WBENCHSCREEN        ;destination screen type
  1695.  
  1696. Gadgets    dc.l    NULL            ;next gadget
  1697.     dc.w    WINDOW_WIDTH-7        ;origin XY of hit box relative to window TopLeft
  1698.     dc.w    13
  1699.  
  1700.     dc.w    15            ;hit box width and
  1701. gad_h    dc.w    100            ;height (FILLED IN)
  1702.     dc.w    NULL            ;gadget flags
  1703.     dc.w    RELVERIFY        ;activation flags
  1704.     dc.w    PROPGADGET        ;gadget type flags
  1705.     dc.l    KnobImage        ;gadget border or image to be rendered
  1706.     dc.l    NULL            ;alternate imagery for selection
  1707.     dc.l    NULL            ;first IntuiText structure
  1708.     dc.l    NULL            ;gadget mutual-exclude long word
  1709.     dc.l    GadgetSInfo        ;SpecialInfo structure
  1710.     dc.w    NULL            ;user-definable data
  1711.     dc.l    NULL            ;pointer to user-definable data
  1712.  
  1713. GadgetSInfo:
  1714.     dc.w    AUTOKNOB+FREEVERT    ;PropInfo flags
  1715.     dc.w    0,$2800            ;horizontal and vertical pot values
  1716.     dc.w    3276,3276        ;horizontal and vertical body values
  1717.     dc.w    0,0,0,0,0,0        ;Intuition initialized and maintained variables
  1718.  
  1719. KnobImage:
  1720.     dc.w    0,$1E            ;XY origin relative to container TopLeft
  1721.     dc.w    7,5            ;Image width and height in pixels
  1722.     dc.w    0            ;number of bitplanes in Image
  1723.     dc.l    NULL            ;pointer to ImageData
  1724.     dc.b    $0000,$0000        ;PlanePick and PlaneOnOff
  1725.     dc.l    NULL            ;next Image structure
  1726.  
  1727. map_newscreen:
  1728.     dc.w    50,0            ;screen XY origin relative to View
  1729.     dc.w    256,256+12        ;screen width and height
  1730.     dc.w    2            ;screen depth (number of bitplanes)
  1731.     dc.b    0,1            ;detail and block pens
  1732.     dc.w    0            ;display modes for this screen
  1733.     dc.w    CUSTOMSCREEN        ;screen type
  1734.     dc.l    NULL            ;pointer to default screen font
  1735.     dc.l    NewScreenName        ;screen title
  1736.     dc.l    NULL            ;first in list of custom screen gadgets
  1737.     dc.l    NULL            ;pointer to custom BitMap structure
  1738.  
  1739. textattr    dc.l    topazname
  1740.         dc.w    CHAR_HEIGHT    ;ta_YSize = 8
  1741.         dc.b    0,0        ;Style and Flags = 0
  1742.  
  1743. topazname    dc.b    "topaz.font",0
  1744.  
  1745. ;-----------------------------------------------
  1746. ; Strings section
  1747. ;-----------------------------------------------
  1748.  
  1749. one        dc.b    "1",0        ;default trace mode
  1750. twenty        dc.b    "20",0        ;default trace update speed
  1751. a_zero        dc.b    "0"        ;a lonely zero char for printing a zero count
  1752. default_conf    dc.b    "S:ISAN.config",0
  1753.  
  1754. NewScreenName    dc.b    "ISAN Opcode Map (Opcode=$0000)",0
  1755.  
  1756. * Tag for VERSION command
  1757. version        dc.b    "$VER: ISAN 1.2 ©LVA 22/JAN/94",0
  1758. WindowName:    dc.b          "ISAN 1.2 ©LVA 22/JAN/94   ("
  1759. window_info    dc.b    "TASK $"
  1760. task_addr_str    dc.b    "XXYYZZQQ)",0    ;**!! Watch out that string doesn't overflow
  1761.  
  1762. regswin_title    dc.b    "Task Registers",0
  1763. prof_win_title    dc.b    "PC Profiling Info",0
  1764.  
  1765. syntax        dc.b    "Example:",LF
  1766.         dc.b    "  1> ISAN PROCESS 5 MODE 2 REGS GRAFMAP",0
  1767.  
  1768. no_arr_mem    dc.b    "Not enough contiguous RAM for statistics arrays.",0
  1769. no_descr_mem    dc.b    "No memory for instruction descriptors array (running LOW!).",0
  1770. dollars_please    dc.b    "Task addresses should have a '$' to denote hexadecimal.",0
  1771. dec_procnum    dc.b    "Process number should be a small decimal number.",0
  1772. no_conf        dc.b    "Couldn't find 'ISAN.config' file anywhere !",0
  1773. bad_conf_file    dc.b    "ISAN.config file contains garbage.",0
  1774. bad_task    dc.b    "Task not found on Waiting or Ready list.",0
  1775. bad_proc    dc.b    "Process not found on Waiting or Ready list.",0
  1776. bad_trace_mode    dc.b    "Trace mode should be 1 or 2 (1=trace all, 2=trace flow)",0
  1777. bad_speed    dc.b    "Speed must be in 1..500 range.",0
  1778. win_too_big    dc.b    "Couldn't open Window (opcode list too long?).",0
  1779. plonker        dc.b    "Please specify either a Task or a Process (not both).",0
  1780. wrong_machine    dc.b    "ISAN Only works on 68020+ machines. Sorry (better than crashing, innit ?)",0
  1781. no_screen_str    dc.b    "Couldn't open Screen for opcode bitmap display.",0
  1782.  
  1783. ISAN_template    dc.b    "TASK/K,PROCESS/K,SPEED/K,MODE/K,REGS/S,TOTAL/S,GRAFMAP/S,FILE/K,PROFILE/S",0
  1784.  
  1785.         EVEN
  1786. hex_output    dc.b    "XXXXYYYY",0
  1787. regstrings    dc.b    "D0=D1=D2=D3=D4=D5=D6=D7="
  1788.         dc.b    "A0=A1=A2=A3=A4=A5=A6=A7=PC="
  1789.  
  1790. total_label    dc.b    "TOTAL"
  1791. underline_label    dc.b    "-----"
  1792.  
  1793. dosname        DOSNAME
  1794. intuiname    INTNAME
  1795. gfxname        GRAFNAME
  1796.  
  1797. ;-----------------------------------------------
  1798. ; Variables (pointers, handles, counters, flags...)
  1799. ;-----------------------------------------------
  1800.  
  1801.         SECTION    isan_vars,BSS
  1802.  
  1803. DOS_LIB_PTR    ds.l    1
  1804. GFX_LIB_PTR    ds.l    1
  1805. INTUI_LIB_PTR    ds.l    1
  1806.  
  1807. stack_level    ds.l    1
  1808. arg_line    ds.l    1
  1809. stdout        ds.l    1
  1810.  
  1811. tcb_ptr        ds.l    1    ;TCB ptr to task we're messing with
  1812. old_trapcode    ds.l    1    ;ptr to original trap exception handler (to restore)
  1813.  
  1814. window        ds.l    1    ;pointer to our Window
  1815. regs_window    ds.l    1    ;-> Registers Window (if requested)
  1816. prof_window    ds.l    1    ;-> PC Profiling Win (if requested)
  1817.  
  1818. rastport    ds.l    1    ;and their RastPorts
  1819. regswin_rp    ds.l    1
  1820. profwin_rp    ds.l    1
  1821.  
  1822. font_ptr    ds.l    1    ;ptr to Topaz Font
  1823.  
  1824. map_screen    ds.l    1    ;ptr to opcode map screen (if asked for)
  1825.  
  1826. msgport        ds.l    1    ;Window's IDCMP Message Port
  1827. imsg_class    ds.l    1
  1828. imsg_iaddr    ds.l    1
  1829. imsg_ratcords    ds.l    1
  1830. imsg_code    ds.w    1
  1831.  
  1832. conf_size    ds.l    1    ;# of configuration file buffer
  1833. conf_buffer    ds.l    1    ;ptr to cached configuration file
  1834.  
  1835. counters    ds.l    1    ;-> 256K of LONG counters (1 long per opcode)
  1836. array_size    ds.l    1    ;szie of descriptor array
  1837. opcode_list    ds.l    1    ;array of opcode descriptors to scan each time
  1838. most_frequent    ds.l    1    ;address of slot representing most frequent opcode
  1839.  
  1840. regs_dump    ds.l    16+1    ;room for D0-D7/A0-USP, PC
  1841.  
  1842. opcodes        ds.w    1    ;# of opcodes to check.
  1843.  
  1844. win_width    ds.w    1
  1845. label_len    ds.w    1
  1846. contents_height    ds.w    1    ;height of used rectangle within window
  1847.  
  1848. close_me    ds.b    1    ;close window request flag
  1849. add_labels    ds.b    1    ;print labels first time only
  1850.  
  1851. num_PCs        ds.w    1    ;number of different non-sequential PCs so far
  1852.  
  1853. PC_history_PCs    ds.l    1    ;ptr to array of encountered PC values
  1854. PC_history_cnts    ds.l    1
  1855.  
  1856. ; Here we have the contiguous block of LONGs that ReadArgs() fills in
  1857. ;--------------------------------------------------------------------
  1858.         EVEN
  1859. rda_results
  1860. task_arg    ds.l    1    ;ptr to TASK address argument
  1861. process_arg    ds.l    1    ;ptr to PROCESS number argument
  1862. update_speed    ds.l    1    ;DOS Delay() value
  1863. trace_mode    ds.l    1    ;1 or 2 for TT=10 or TT=01
  1864. show_regs    ds.l    1    ;open extra Window to display Task's register set
  1865. total_flag    ds.l    1
  1866. opcode_map    ds.l    1    ;open opcode map screen
  1867. conf_file    ds.l    1    ;ptr to filename for configuration
  1868. profile_flag    ds.l    1    ;do PC profiling in MODE 2 tracing
  1869.  
  1870.  
  1871.         END
  1872.